package model

import (
	"github.com/morgine/redirect/internal/model/cache"
	"gorm.io/gorm"
	"sync"
	"time"
)

type DB struct {
	db     *gorm.DB
	caches map[int]*cache.Group
	mu     sync.Mutex
}

func (db *DB) reloadGroup(groupID int) error {
	db.mu.Lock()
	defer db.mu.Unlock()
	links, err := db.GetLinks(groupID)
	if err != nil {
		return err
	}
	if exist := db.caches[groupID]; exist != nil {
		exist.Close()
		delete(db.caches, groupID)
	}
	var cacheLinks []*cache.Link
	for _, link := range links {
		if link.Url != "" {
			start, err := time.ParseInLocation("15:04", link.Start, time.Local)
			if err != nil {
				return err
			}
			stop, err := time.ParseInLocation("15:04", link.Stop, time.Local)
			if err != nil {
				return err
			}
			var cacheLink = &cache.Link{
				Url:              &link.Url,
				StartDateMinutes: cache.GetDateTimeMinutes(start),
				StopDateMinutes:  cache.GetDateTimeMinutes(stop),
			}
			cacheLinks = append(cacheLinks, cacheLink)
		}
	}
	if len(cacheLinks) > 0 {
		db.caches[groupID] = cache.NewGroup(cacheLinks)
	}
	return nil
}

func (db *DB) delCache(groupID int) {
	db.mu.Lock()
	defer db.mu.Unlock()
	if exist := db.caches[groupID]; exist != nil {
		exist.Close()
		delete(db.caches, groupID)
	}
}

func (db *DB) initCaches() error {
	groups, err := db.GetGroups()
	if err != nil {
		return err
	}
	for _, group := range groups {
		err = db.reloadGroup(group.ID)
		if err != nil {
			return err
		}
	}
	return nil
}

func (db *DB) Close() {
	db.mu.Lock()
	defer db.mu.Unlock()
	for _, group := range db.caches {
		group.Close()
	}
}

// 获取当前分组的目的地址，如果地址不存在，则获取默认分组的目的地址
func (db *DB) GetCurrentDestination(groupID int) *string {
	db.mu.Lock()
	defer db.mu.Unlock()
	url := db.getCurrentDestination(groupID)
	if url == nil && groupID != 1 {
		return db.getCurrentDestination(1)
	}
	return url
}

func (db *DB) getCurrentDestination(groupID int) *string {
	if exist := db.caches[groupID]; exist != nil {
		return exist.GetCurrentUrl()
	}
	return nil
}

func NewDB(db *gorm.DB) *DB {
	err := db.AutoMigrate(&Group{}, &Link{})
	if err != nil {
		panic(err)
	}
	d := &DB{db: db, caches: map[int]*cache.Group{}}
	err = d.initCaches()
	if err != nil {
		panic(err)
	}
	return d
}
